﻿using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace SimJsonRpc
{
    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddRpcServer<T>(
           this IServiceCollection services,
           IRpcServerOptions<T> serverOptions) where T : class, IRpcServer, new()
        {
            if (serverOptions == null)
            {
                throw new ArgumentNullException(nameof(serverOptions));
            }

            var serverTransport = new T();

            services.AddSingleton<IRpcServer>(serverTransport);
            services.AddTransient<IRpcInvoker, DefaultRpcInvoker>();
            serverTransport.ConfigureServices(services, serverOptions);

            var serviceImplTypes = GetServices();
            foreach (var item in serviceImplTypes)
            {
                var interfaceType = item.GetInterfaces()[0];
                //if (interfaceType.IsValidedAopService(cache))
                //{
                services.AddTransient(typeof(IService), item);
                services.TryAddTransient(interfaceType, item);
                //}
            }
            return services;
        }

        public static IApplicationBuilder UseSimRpcServer(this IApplicationBuilder builder)
        {
            builder.ApplicationServices.GetService<IRpcServer>().Configure(builder);
            return builder;
        }

        private static List<TypeInfo> GetServices()
        {
            List<TypeInfo> allService = new List<TypeInfo>();
            allService.AddRange(Assembly.GetEntryAssembly()
                 .DefinedTypes
                 .Where(p => typeof(IService).IsAssignableFrom(p) && !p.GetTypeInfo().IsInterface)
                .ToList());
            allService.AddRange(Assembly
            .GetEntryAssembly()
            .GetReferencedAssemblies()
            .Select(Assembly.Load)
            .SelectMany(x => x.DefinedTypes)
            .Where(p => typeof(IService).IsAssignableFrom(p) && !p.GetTypeInfo().IsInterface)
            .ToList());
            return allService;
        }
    }
}
